package com.duck.inspection.utils;

import com.duck.inspection.domain.dto.DuckCountDto;
import com.duck.inspection.domain.po.DuckMetricsPojo;
import com.duck.inspection.enums.DuckAgeStage;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Component
public class DuckMetricsGenerator {
    private static final SecureRandom random = new SecureRandom();
    private static final double GROWTH_VARIATION = 0.15; // 生长波动率

    public List<DuckMetricsPojo> generate(DuckCountDto request) {
        DuckAgeStage stage = DuckAgeStage.fromCode(request.getAgeCode());

        return IntStream.rangeClosed(1, request.getCount())
                .mapToObj(id -> generateDuck(id, stage))
                .collect(Collectors.toList());
    }

    private DuckMetricsPojo generateDuck(int id, DuckAgeStage stage) {
        double ageMonth = calculatePreciseAge(stage);

        return new DuckMetricsPojo()
                .setId(id)
                .setAgeStageCode(stage.getCode())
                .setDisplayAge(stage.getDisplayName())
                .setAgeMonth(ageMonth)
                .setWeight(generateWeight(ageMonth))
                .setBodyLength(generateBodyLength(ageMonth))
                .setNeckLength(generateNeckLength(ageMonth))
                .setDivingLength(generateDivingLength(ageMonth))
                .setKeelLength(generateKeelLength(ageMonth))
                .setChestWidth(generateChestWidth(ageMonth))
                .setChestDepth(generateChestDepth(ageMonth))
                .setTibiaLength(generateTibiaLength(ageMonth));
    }

    // 年龄精确计算（带随机波动）
    private double calculatePreciseAge(DuckAgeStage stage) {
        return switch (stage) {
            case WEEK1 -> randomRange(0.2, 0.3);   // 5-7天
            case WEEK2 -> randomRange(0.4, 0.6);   // 10-14天
            case WEEK3 -> randomRange(0.7, 0.9);   // 17-21天
            case MONTH1 -> randomRange(1.0, 1.1);  // 1个月
            case MONTH2 -> randomRange(2.0, 2.2);
            case MONTH3 -> randomRange(3.0, 3.2);
            case MONTH4 -> randomRange(4.0, 4.3);
            case MONTH5 -> randomRange(5.0, 5.5);
            case MONTH6_PLUS -> randomRange(6.0, 12.0);
        };
    }

    //-- 各指标生成算法 --
    private Double generateWeight(double ageMonth) {
        double baseWeight = switch ((int) (ageMonth * 4)) { // 转换为周
            case 0,1 -> 0.15 + ageMonth * 0.2;  // 1周龄
            case 2,3 -> 0.3 + ageMonth * 0.3;   // 2-3周
            case 4 -> 0.8;                      // 1个月
            case 5,6,7,8 -> 1.2 + (ageMonth-2)*0.5;
            default -> 2.8 + (ageMonth-6)*0.1;  // 6+个月
        };
        return round(baseWeight * (1 + (random.nextDouble()-0.5)*GROWTH_VARIATION), 2);
    }

    private Double generateBodyLength(double ageMonth) {
        double baseLength = ageMonth < 1 ?
                15 + ageMonth*40 : // 幼雏快速生长
                28 + ageMonth*0.5; // 成年缓慢生长
        return round(baseLength * growthFactor(), 1);
    }

    private Double generateNeckLength(double ageMonth) {
        double base = Math.min(ageMonth * 4, 14) + random.nextDouble()*2;
        return round(base, 1);
    }

    private Double generateDivingLength(double ageMonth) {
        double base = 20 + ageMonth * 4;
        return constrain(base, 35, 45);
    }

    private Double generateKeelLength(double ageMonth) {
        return round(ageMonth * 3 + random.nextDouble()*2, 1);
    }

    private Double generateChestWidth(double ageMonth) {
        double base = ageMonth < 3 ?
                8 + ageMonth*2 :
                12 + ageMonth*0.3;
        return round(base, 1);
    }

    private Double generateChestDepth(double ageMonth) {
        return round(10 + ageMonth * 0.5 + random.nextDouble(), 1);
    }

    private Double generateTibiaLength(double ageMonth) {
        double base = 2.5 + ageMonth * 1.2;
        return round(base + (random.nextGaussian()*0.3), 1);
    }

    //-- 工具方法 --
    private double randomRange(double min, double max) {
        return min + (max - min) * random.nextDouble();
    }

    private double growthFactor() {
        return 0.95 + random.nextDouble()*0.1;
    }

    private double constrain(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }

    private double round(double value, int decimal) {
        return BigDecimal.valueOf(value)
                .setScale(decimal, RoundingMode.HALF_UP)
                .doubleValue();
    }
}